//
//  Monster.cpp
//  FruitCrush
//
//  Created by gaoyu on 15/7/9.
//
//

#include "Monster.h"
#include "ScoreNumberWidget.h"
#include "MonsterPropertyView.h"
#include "AttackAction.h"
#include "ShowStringWidget.h"
#include "LocalizedStringGetter.h"

USING_NS_CC;

#define MONSTER_WIDTH   100
#define MONSTER_HEIGHT  100
#define HP_Y_PAD        (-10)
#define PROPERTY_VIEW_X (MONSTER_WIDTH -25)
#define PROPERTY_VIEW_Y 0
#define MAX_HP_LEVEL    (10)
#define BOSS_ATTACK_TIME_GAP    (10)
#define COVER_X     (-25)
#define COVER_Y     (-26)

typedef enum {
    ZBg = 0,
    ZBossBarNext,
    ZBar,
    ZProverty,
    ZCover,
} Zindex;

typedef enum {
    TagBase,
    TagCover,
} Tag;

Monster::Monster()
: hp(0)
, maxHp(0)
, healthBar(NULL)
, m_isBoss(false)
, m_nowHpLevel(0)
,m_swordProperty(MonsterPropertyTypeNone)
,m_arrowProperty(MonsterPropertyTypeNone)
,m_fireProperty(MonsterPropertyTypeNone)
,m_lightProperty(MonsterPropertyTypeNone)
,bossHpBarNext(NULL)
,lastTime(0)
,m_isPause(false)
,m_isCover(false)
{
}

Monster* Monster::create(int type)
{
    Monster *pRet = new(std::nothrow) Monster();
    if (pRet && pRet->init(type)){
        pRet->autorelease();
        return pRet;
    }
    else
    {
        delete pRet;
        pRet = NULL;
        return NULL;
    }
}

bool Monster::init(int type)
{
    if (!Layer::init()) {
        return false;
    }
    m_nowHpLevel = MAX_HP_LEVEL-1;
    m_isBoss = MonsterConfig::isBoss(type);
    m_isCover = MonsterConfig::isCover(type);
    
    spriteInit(type);
    if(m_isBoss){
    	bossHealthBarInit(type);
    }else{
    	healthBarInit(type);
    }
    if(m_isCover)
    {
    	protectCoverInit();
    }

    propertyInit(type);
    scheduleUpdate();
    return true;
}

void Monster::propertyInit(int type)
{
    auto monsterPropertyView = MonsterPropertyView::create();
    monsterPropertyView->setPosition(Point(PROPERTY_VIEW_X,PROPERTY_VIEW_Y));
    addChild(monsterPropertyView,ZProverty);
    
    m_swordProperty = MonsterConfig::getSwordProperty(type);
    if(m_swordProperty == MonsterPropertyTypeWeak){
        monsterPropertyView->addPropertyState(MonsterPropertyShowTypeSwordWeak);
    }else if(m_swordProperty == MonsterPropertyTypeImmune){
        monsterPropertyView->addPropertyState(MonsterPropertySHowTypeSwordImmune);
    }
    m_arrowProperty = MonsterConfig::getArrowProperty(type);
    if(m_arrowProperty == MonsterPropertyTypeWeak){
        monsterPropertyView->addPropertyState(MonsterPropertyShowTypeArrowWeak);
    }else if(m_arrowProperty == MonsterPropertyTypeImmune){
        monsterPropertyView->addPropertyState(MonsterPropertySHowTypeArrowImmune);
    }
    m_fireProperty = MonsterConfig::getFireProperty(type);
    if(m_fireProperty == MonsterPropertyTypeWeak){
        monsterPropertyView->addPropertyState(MonsterPropertyShowTypeFireWeak);
    }else if(m_fireProperty == MonsterPropertyTypeImmune){
        monsterPropertyView->addPropertyState(MonsterPropertySHowTypeFireImmune);
    }
    m_lightProperty = MonsterConfig::getLightProperty(type);
    if(m_lightProperty == MonsterPropertyTypeWeak){
        monsterPropertyView->addPropertyState(MonsterPropertyShowTypeLightWeak);
    }else if(m_lightProperty == MonsterPropertyTypeImmune){
        monsterPropertyView->addPropertyState(MonsterPropertySHowTypeLightImmune);
    }
}

void Monster::spriteInit(int type)
{
    auto cache = SpriteFrameCache::getInstance();
    cache->addSpriteFramesWithFile("Monsters.plist");
    
    __String *fileName = __String::createWithFormat("Monster%d.png",type);
    auto monster = Sprite::createWithSpriteFrameName(fileName->getCString());
    monster->setAnchorPoint(Vec2::ZERO);
    monster->setPosition(Vec2::ZERO);
    this->addChild(monster);
}

void Monster::healthBarInit(int type)
{
    maxHp = MonsterConfig::getMonsterHp(type);
    hp = maxHp;
	auto sprite = Sprite::createWithSpriteFrameName("MonsterHpBar.png");
	healthBar= ProgressTimer::create(sprite);
    healthBar->setAnchorPoint(Vec2::ZERO);
	healthBar->setPosition(Point(0,HP_Y_PAD));
    addChild(healthBar,ZBar);
    healthBar->setType(ProgressTimer::Type::BAR);
    healthBar->setPercentage(100);
    healthBar->setMidpoint(Point(0,0));
    healthBar->setBarChangeRate(Point(1,0));
    
    auto hpBg = Sprite::createWithSpriteFrameName("MonsterHpBg.png");
    hpBg->setAnchorPoint(Vec2::ZERO);
    hpBg->setPosition(Point(0,HP_Y_PAD));
    addChild(hpBg);
}

void Monster::bossHealthBarInit(int type)
{
    maxHp = MonsterConfig::getMonsterHp(type);
    hp = maxHp;
	__String *file = __String::create("");
	file->initWithFormat("BossHpBar%d.png",m_nowHpLevel);
	auto sprite = Sprite::createWithSpriteFrameName(file->getCString());
	healthBar= ProgressTimer::create(sprite);
    healthBar->setAnchorPoint(Vec2::ZERO);
	healthBar->setPosition(Point(0,HP_Y_PAD));
    addChild(healthBar,ZBar);
    healthBar->setType(ProgressTimer::Type::BAR);
    healthBar->setPercentage(100);
    healthBar->setMidpoint(Point(0,0));
    healthBar->setBarChangeRate(Point(1,0));

    auto hpBg = Sprite::createWithSpriteFrameName("MonsterHpBg.png");
    hpBg->setAnchorPoint(Vec2::ZERO);
    hpBg->setPosition(Point(0,HP_Y_PAD));
    addChild(hpBg);

    changeBossBarNext();

}

int Monster::getPropertyByAttackType(int attackType)
{
    switch (attackType) {
        case SwordAttack: return m_swordProperty;
        case ArrowAttack: return m_arrowProperty;
        case FireAttack: return m_fireProperty;
        case LightAttack: return m_lightProperty;

    }
    return MonsterPropertyTypeNone;

}

bool Monster::checkZeroDamage(int damage)
{
    if(damage == 0){
        auto *widget = ShowStringWidget::create();
        widget->setText(LocalizedStringGetter::getStringByKey("Immune"));
        widget->setPosition(Point(MONSTER_WIDTH/2,MONSTER_HEIGHT/2));
        addChild(widget);
    	return true;
    }
    return false;
}

bool Monster::checkCoverModel()
{
    if(m_isCover){
        auto *widget = ShowStringWidget::create();
        widget->setText(LocalizedStringGetter::getStringByKey("Invalid"));
        widget->setPosition(Point(MONSTER_WIDTH/2,MONSTER_HEIGHT/2));
        addChild(widget);
    	return true;
    }
    return false;
}

bool Monster::changeHealth(int gap,int attackType,int doubleNum)
{
    bool result = false;
    int hpChangeBase = getHpChange(gap,attackType);
    int hpChange = hpChangeBase*doubleNum;
    
    if(checkZeroDamage(hpChange)){
    	return false;
    }

    if(checkCoverModel()){
    	return false;
    }


	hp -= hpChange;
    if(hp <= 0){
        hp = 0;
        result = true;
    }
    healthBarChange();
    showLostHp(hpChange,attackType,doubleNum);
    showBeAttackAction();
    return result;
}

void Monster::addHealth(int num)
{
    hp += num;
    if(hp > maxHp){
        hp = maxHp;
    }
    healthBarChange();
    showAddHp(num);
}

void Monster::healthBarChange()
{
	if(m_isBoss){
        if(!(hp > m_nowHpLevel*maxHp/MAX_HP_LEVEL&&
		   hp <= (m_nowHpLevel+1)*maxHp/MAX_HP_LEVEL)){
        	gotoRightLevel();
		}
		healthBar->setPercentage(100*(hp-m_nowHpLevel*maxHp/MAX_HP_LEVEL)/(maxHp/MAX_HP_LEVEL));
	}else{
		healthBar->setPercentage(100*hp/maxHp);
	}
}

void Monster::gotoRightLevel()
{
    while(hp <= m_nowHpLevel*maxHp/MAX_HP_LEVEL){
    	m_nowHpLevel--;
    }
    while(hp > (m_nowHpLevel+1)*maxHp/MAX_HP_LEVEL){
    	m_nowHpLevel++;
    }
    changeHealthBarByLevel();
}

void Monster::changeHealthBarByLevel()
{
    if(m_nowHpLevel-1>=0){
        __String *file = __String::create("");
        file->initWithFormat("BossHpBar%d.png",m_nowHpLevel);
        auto sprite = Sprite::createWithSpriteFrameName(file->getCString());
        healthBar->setSprite(sprite);
    }
	changeBossBarNext();
}

void Monster::changeBossBarNext()
{
    this->removeChild(bossHpBarNext);
    if(m_nowHpLevel-1>=0){
        __String *file = __String::create("");
        file->initWithFormat("BossHpBar%d.png",m_nowHpLevel-1);
        bossHpBarNext = Sprite::createWithSpriteFrameName(file->getCString());
        bossHpBarNext->setAnchorPoint(Vec2::ZERO);
        bossHpBarNext->setPosition(Point(0,HP_Y_PAD));
        addChild(bossHpBarNext,ZBossBarNext);
    }

}


int Monster::getHpChange(int gap,int attackType)
{
    int property = getPropertyByAttackType(attackType);
    int hpChange = gap;
    if(property == MonsterPropertyTypeWeak){
        hpChange = hpChange*2;
    }else if(property == MonsterPropertyTypeImmune){
        hpChange = 0;
    }
    return hpChange;
}

void Monster::showLostHp(int hp,int attackType,int doubleNum)
{
    auto *widget = ScoreNumberWidget::create();
    int property = getPropertyByAttackType(attackType);

    if(property == MonsterPropertyTypeImmune){
            return;
    }

    if(property == MonsterPropertyTypeWeak||doubleNum > 1){
        widget->setStrongNum(-hp);
    }else{
        widget->setNum(-hp);
    }
    widget->setPosition(Point(MONSTER_WIDTH/2,MONSTER_HEIGHT/2));
    addChild(widget);
}

void Monster::showAddHp(int hp)
{
    auto *widget = ScoreNumberWidget::create();
    widget->setHealthNum(hp);
    widget->setPosition(Point(MONSTER_WIDTH/2,MONSTER_HEIGHT/2));
    addChild(widget);
}

Size Monster::getSize()
{
    return Size(MONSTER_WIDTH,MONSTER_HEIGHT);
}

void Monster::showBeAttackAction()
{
    this->stopAllActions();
    this->runAction(JumpBy::create(0.4, Vec2::ZERO, 10, 1));
}

void Monster::setCallback(const monsterBossAttackCallback& callback)
{
    _callback = callback;
}

void Monster::update(float dt)
{
	if(m_isPause) return;

	if(m_isBoss){
	    if(lastTime < BOSS_ATTACK_TIME_GAP){
	        lastTime += dt;
	    }else{
	        lastTime = 0;
	        _callback(this);
	        showBossAttackAction();
	    }
	}

}

void Monster::showBossAttackAction()
{
    this->stopAllActions();
    this->runAction(JumpBy::create(0.3, Vec2::ZERO, -20, 1));
}

void Monster::protectCoverInit()
{
    auto cover = Sprite::createWithSpriteFrameName("ProtectCover.png");
    cover->setAnchorPoint(Vec2::ZERO);
    cover->setPosition(COVER_X,COVER_Y);
    this->addChild(cover,ZCover,TagCover);
}

void Monster::destoryProtectCover()
{
	if(m_isCover){
		removeChildByTag(TagCover);
		m_isCover = false;
	}
}
